#include "mainwindow.h"
#include "../../src/common/utils/utils.h"

#include <DTitlebar>
#include <DDialog>

#include <QVBoxLayout>
#include <QTextEdit>
#include <QApplication>

#define APP_THEME_ICON_DEFAULT "application-x-executable"

// 各列参数检索
#define COL_INDEX_PID 0
#define COL_INDEX_DATA 0
#define COL_INDEX_NAME 1
#define COL_INDEX_UPLOAD_SPEED 2
#define COL_INDEX_DOWNLOAD_SPEED 3
#define COL_INDEX_TOTAL_SPEED 4

#define ITEM_DATA_ROLE_USER Qt::ItemDataRole::UserRole
#define ITEM_DATA_ROLE_SORTING ITEM_DATA_ROLE_USER // 排序数据角色
#define ITEM_DATA_ROLE_NEED_REMOVE ITEM_DATA_ROLE_USER + 1
#define ITEM_DATA_ROLE_PID ITEM_DATA_ROLE_USER + 2
#define ITEM_DATA_ROLE_NAME ITEM_DATA_ROLE_USER + 3
#define ITEM_DATA_ROLE_PROC_NAME ITEM_DATA_ROLE_USER + 4
#define ITEM_DATA_ROLE_EXEC_PATH ITEM_DATA_ROLE_USER + 5
#define ITEM_DATA_ROLE_DESKTOP_PATH ITEM_DATA_ROLE_USER + 6
#define ITEM_DATA_ROLE_PKG_NAME ITEM_DATA_ROLE_USER + 7
#define ITEM_DATA_ROLE_THEME_ICON ITEM_DATA_ROLE_USER + 8
#define ITEM_DATA_ROLE_UPLOAD_SPEED ITEM_DATA_ROLE_USER + 9
#define ITEM_DATA_ROLE_DOWNLOAD_SPEED ITEM_DATA_ROLE_USER + 10

MainWindow::MainWindow(QWidget *parent)
    : DBlurEffectWidget(parent)
    , m_model(new ProcInfoModel(this))
    , m_settingsAction(nullptr)
    , m_createProcCleanerDesktopAction(nullptr)
    , m_settingsPage(nullptr)
    , m_updateTimer(nullptr)
    , m_listViewItemModel(nullptr)
    , m_tableView(nullptr)
    , m_listViewSelectionModel(nullptr)
    , m_sortingIndex(COL_INDEX_TOTAL_SPEED)
    , m_sortingOrder(Qt::SortOrder::DescendingOrder)
{
    initUI();
    initData();
    initConnections();
    postInit();
}

MainWindow::~MainWindow()
{
}

void MainWindow::openSettingsPage()
{
    if (!m_settingsPage) {
        m_settingsPage = new SettingsWidget(m_model);
        connect(m_settingsPage, &SettingsWidget::closed, this, [this]{
           m_settingsPage->deleteLater();
           m_settingsPage = nullptr;
        });
    }
    m_settingsPage->show();
}

void MainWindow::onContextMenuTriggered(QAction *action)
{
    if (m_detailAction == action) {
        ProcInfo info;
        QModelIndexList indexList = m_listViewSelectionModel->selectedIndexes();
        if (!indexList.isEmpty()) {
            info = getInfoFromModel(indexList.first().row());
        }

        QString infoStr = QString("pid：%1\n包名：%2\n软件名：%3\n进程名：%4\n执行路径：%5\n桌面文件路径：%6\n")
                              .arg(info.nPid)
                              .arg(info.sPkgName)
                              .arg(info.sAppName)
                              .arg(info.sProcName)
                              .arg(info.sExecPath)
                              .arg(info.sDesktopPath);

        DDialog dlg;

        QTextEdit *edit = new QTextEdit(&dlg);
        QPalette pa = edit->palette();
        pa.setColor(QPalette::ColorRole::Base, Qt::transparent);
        edit->setPalette(pa);
        edit->setLineWidth(0);
        edit->setReadOnly(true);
        edit->setText(infoStr);

        dlg.addContent(edit);
        dlg.exec();
    }
}

void MainWindow::closeEvent(QCloseEvent *e)
{
    DBlurEffectWidget::closeEvent(e);
    qApp->exit();
}

void MainWindow::initUI()
{
    setMinimumSize(600, 400);
    setMaskAlpha(150);
    resize(900, 540);

    QVBoxLayout *mainLayout = new QVBoxLayout;
    mainLayout->setContentsMargins(0, 0, 0, 0);
    mainLayout->setSpacing(0);
    setLayout(mainLayout);

    DTitlebar *titlebar = new DTitlebar(this);
    titlebar->setBackgroundTransparent(true);
    titlebar->setTitle(qApp->applicationName());
    titlebar->setIcon(QIcon::fromTheme("waterflow"));
    titlebar->setFixedHeight(40);
    mainLayout->addWidget(titlebar);

    // 设置
    m_settingsAction = new QAction("设置", this);
    m_settingsAction->setCheckable(false);
    titlebar->menu()->addAction(m_settingsAction);
    // 在桌面创建内存清理启动文件
    m_createProcCleanerDesktopAction = new QAction("在桌面创建内存清理启动文件", this);
    m_createProcCleanerDesktopAction->setCheckable(false);
    titlebar->menu()->addAction(m_createProcCleanerDesktopAction);

    QWidget *contentWidget = new QWidget(this);
    mainLayout->addWidget(contentWidget, 1);

    QVBoxLayout *contentLayout = new QVBoxLayout;
    contentLayout->setContentsMargins(3, 0, 3, 3);
    contentWidget->setLayout(contentLayout);

    // 添加内容
    m_listViewItemModel = new QStandardItemModel(this);
    // 设置排序数据角色
    m_listViewItemModel->setSortRole(ITEM_DATA_ROLE_SORTING);
    m_listViewItemModel->setHorizontalHeaderLabels({"pid", "名称", "上传", "下载", "总网速"});

    m_tableView = new CTableView(this);
    m_tableView->setFocusPolicy(Qt::FocusPolicy::StrongFocus);

    // 可以显示菜单
    m_tableView->setContextMenuPolicy(Qt::ContextMenuPolicy::CustomContextMenu);
    m_tableView->setSelectionMode(QAbstractItemView::SelectionMode::SingleSelection);
    m_tableView->setEditTriggers(QTableView::EditTrigger::NoEditTriggers);
    m_tableView->setTextElideMode(Qt::TextElideMode::ElideNone);
    m_tableView->setHeaderBgTransparent(true);
    m_tableView->setTextElideMode(Qt::TextElideMode::ElideMiddle);
    m_tableView->setSortingEnabled(true);
    m_tableView->setModel(m_listViewItemModel);

    m_tableView->horizontalHeader()->setSortIndicatorShown(true);
    m_tableView->horizontalHeader()->setSectionsClickable(true);
    m_tableView->horizontalHeader()->resizeSection(0, 100);
    m_tableView->horizontalHeader()->resizeSection(1, 200);
    m_tableView->horizontalHeader()->resizeSection(2, 150);
    m_tableView->horizontalHeader()->resizeSection(3, 150);
    m_tableView->horizontalHeader()->setStretchLastSection(true);
    contentLayout->addWidget(m_tableView);

    // context menu
    m_contextMenu = new QMenu(this);
    m_detailAction = new QAction("详情", this);
    m_contextMenu->addAction(m_detailAction);
    m_contextMenu->hide();
}

void MainWindow::initData()
{
    m_listViewSelectionModel = m_tableView->selectionModel();

    m_updateTimer = new QTimer(this);
    m_updateTimer->setInterval(2 * 1000);
}

void MainWindow::initConnections()
{
    connect(m_settingsAction, &QAction::triggered, this, [this](bool checked) {
        Q_UNUSED(checked);
        openSettingsPage();
    });
    connect(m_createProcCleanerDesktopAction, &QAction::triggered, this, [this](bool checked) {
        Q_UNUSED(checked);
        m_model->createProcCleanerDesktop();
    });

    connect(m_model, &ProcInfoModel::showNetUnKnownItemSwitchChanged, this, [this](bool show) {
        if (!show) {
            this->hideUnknownItem();
        }
    });

    // 表头排序标签改变
    connect(m_tableView->horizontalHeader(), &QHeaderView::sortIndicatorChanged, this, [this](int index, Qt::SortOrder order) {
        m_sortingIndex = index;
        m_sortingOrder = order;
        // 根据当前排序状态排序
        m_listViewItemModel->sort(m_sortingIndex, m_sortingOrder);
    });

    // 右键菜单
    connect(m_tableView, &CTableView::customContextMenuRequested, this, [this](const QPoint &) {
        m_contextMenu->popup(QCursor::pos());
    });

    connect(m_contextMenu, &QMenu::triggered, this, &MainWindow::onContextMenuTriggered);

    // 更新定时器
    connect(m_updateTimer, &QTimer::timeout, this, &MainWindow::updateProcInfo);
}

void MainWindow::postInit()
{
    // 设置初始排序
    m_tableView->horizontalHeader()->setSortIndicator(COL_INDEX_TOTAL_SPEED, Qt::SortOrder::DescendingOrder);

    updateProcInfo();
    m_updateTimer->start();
}

void MainWindow::updateProcInfo()
{
    ProcInfoList procInfoList = m_model->getProcInfoList();

    // 先设置所有项为待移除项
    for (int rowIndex = 0; rowIndex < m_listViewItemModel->rowCount(); rowIndex++) {
        QStandardItem *item = m_listViewItemModel->item(rowIndex, COL_INDEX_DATA);
        item->setData(true, ITEM_DATA_ROLE_NEED_REMOVE);
    }

    for (int i = procInfoList.size() - 1; i >= 0; i--) {
        const ProcInfo &info = procInfoList.at(i);
        // 找出相同进程,并更新
        bool hasSame = false;
        for (int rowIndex = 0; rowIndex < m_listViewItemModel->rowCount(); rowIndex++) {
            const ProcInfo infoTmp = getInfoFromModel(rowIndex);
            if (info.nPid == infoTmp.nPid) {
                // pid
                QStandardItem *pidItem = m_listViewItemModel->item(rowIndex, COL_INDEX_PID);

                // name
                QStandardItem *nameItem = m_listViewItemModel->item(rowIndex, COL_INDEX_NAME);

                // upload speed
                QStandardItem *uploadSpeedItem = m_listViewItemModel->item(rowIndex, COL_INDEX_UPLOAD_SPEED);

                // download speed
                QStandardItem *downloadSpeedItem = m_listViewItemModel->item(rowIndex, COL_INDEX_DOWNLOAD_SPEED);

                // total speed
                QStandardItem *totalSpeedItem = m_listViewItemModel->item(rowIndex, COL_INDEX_TOTAL_SPEED);

                setInfoForItems(info, pidItem, nameItem, uploadSpeedItem, downloadSpeedItem, totalSpeedItem);

                hasSame = true;
                break;
            }
        }

        if (hasSame) {
            procInfoList.removeAt(i);
        }
    }

    // 移除已经退出的进程
    for (int rowIndex = m_listViewItemModel->rowCount() - 1; rowIndex >= 0; rowIndex--) {
        QStandardItem *item = m_listViewItemModel->item(rowIndex, COL_INDEX_DATA);
        bool needRemove = item->data(ITEM_DATA_ROLE_NEED_REMOVE).toBool();
        if (needRemove) {
            m_listViewItemModel->removeRow(rowIndex);
        }
    }

    // 添加新进程
    for (const ProcInfo &info : procInfoList) {
        // 是否隐藏未知项
        if (!m_model->isShowNetUnKnownItem() && 0 == info.nPid) {
            continue;
        }

        // pid
        QStandardItem *pidItem = new QStandardItem;

        // name
        QStandardItem *nameItem = new QStandardItem;

        // upload speed
        QStandardItem *uploadSpeedItem = new QStandardItem;

        // download speed
        QStandardItem *downloadSpeedItem = new QStandardItem;

        // total speed
        QStandardItem *totalSpeedItem = new QStandardItem;

        setInfoForItems(info, pidItem, nameItem, uploadSpeedItem, downloadSpeedItem, totalSpeedItem);
        // append
        m_listViewItemModel->appendRow({pidItem, nameItem, uploadSpeedItem, downloadSpeedItem, totalSpeedItem});
    }

    // 根据当前排序状态排序
    m_listViewItemModel->sort(m_sortingIndex, m_sortingOrder);
}

ProcInfo MainWindow::getInfoFromModel(int row)
{
    ProcInfo info;
    QModelIndex index = m_listViewItemModel->index(row, COL_INDEX_DATA);
    info.nPid = index.data(ITEM_DATA_ROLE_PID).toInt();
    info.sAppName = index.data(ITEM_DATA_ROLE_NAME).toString();
    info.sProcName = index.data(ITEM_DATA_ROLE_PROC_NAME).toString();
    info.sExecPath = index.data(ITEM_DATA_ROLE_EXEC_PATH).toString();
    info.sDesktopPath = index.data(ITEM_DATA_ROLE_DESKTOP_PATH).toString();
    info.sPkgName = index.data(ITEM_DATA_ROLE_PKG_NAME).toString();
    info.sThemeIcon = index.data(ITEM_DATA_ROLE_THEME_ICON).toString();
    info.dUploadSpeed = index.data(ITEM_DATA_ROLE_UPLOAD_SPEED).toDouble();
    info.dDownloadSpeed = index.data(ITEM_DATA_ROLE_DOWNLOAD_SPEED).toDouble();

    return info;
}

void MainWindow::setInfoForItems(const ProcInfo &info, QStandardItem *pidItem, QStandardItem *nameItem, QStandardItem *uploadSpeedItem, QStandardItem *downloadSpeedItem, QStandardItem *totalSpeedItem)
{
    // pid
    pidItem->setData(info.nPid, Qt::ItemDataRole::DisplayRole);
    pidItem->setData(info.nPid, ITEM_DATA_ROLE_SORTING);

    // name
    QString appName = getAppNameFromDesktop(info.sDesktopPath);
    QString name = appName.isEmpty() ? info.sProcName : appName;
    nameItem->setData(name, Qt::ItemDataRole::DisplayRole);
    nameItem->setData(name, ITEM_DATA_ROLE_SORTING);

    if (nameItem->data(Qt::ItemDataRole::DecorationRole).isNull()) {
        QIcon icon = info.sThemeIcon.isEmpty() ? QIcon::fromTheme(APP_THEME_ICON_DEFAULT)
                                               : QIcon::fromTheme(info.sThemeIcon);
        nameItem->setData(icon, Qt::ItemDataRole::DecorationRole);
    }

    // upload speed
    QString uploadSpeedStr = formatBytes(info.dUploadSpeed, 2).append("/s");
    uploadSpeedItem->setData(uploadSpeedStr, Qt::ItemDataRole::DisplayRole);
    // 排序
    uploadSpeedItem->setData(info.dUploadSpeed, ITEM_DATA_ROLE_SORTING);

    // download speed
    QString downloadSpeedStr = formatBytes(info.dDownloadSpeed, 2).append("/s");
    downloadSpeedItem->setData(downloadSpeedStr, Qt::ItemDataRole::DisplayRole);
    // 排序
    downloadSpeedItem->setData(info.dDownloadSpeed, ITEM_DATA_ROLE_SORTING);

    // total speed
    double totalSpeed = info.dUploadSpeed + info.dDownloadSpeed;
    QString totalSpeedStr = formatBytes(totalSpeed, 2).append("/s");
    totalSpeedItem->setData(totalSpeedStr, Qt::ItemDataRole::DisplayRole);
    // 排序
    totalSpeedItem->setData(totalSpeed, ITEM_DATA_ROLE_SORTING);

    // data
    pidItem->setData(false, ITEM_DATA_ROLE_NEED_REMOVE);
    pidItem->setData(info.nPid, ITEM_DATA_ROLE_PID);
    pidItem->setData(name, ITEM_DATA_ROLE_NAME);
    pidItem->setData(info.sProcName, ITEM_DATA_ROLE_PROC_NAME);
    pidItem->setData(info.sExecPath, ITEM_DATA_ROLE_EXEC_PATH);
    pidItem->setData(info.sDesktopPath, ITEM_DATA_ROLE_DESKTOP_PATH);
    pidItem->setData(info.sThemeIcon, ITEM_DATA_ROLE_THEME_ICON);
    pidItem->setData(info.sPkgName, ITEM_DATA_ROLE_PKG_NAME);
    pidItem->setData(info.dUploadSpeed, ITEM_DATA_ROLE_UPLOAD_SPEED);
    pidItem->setData(info.dDownloadSpeed, ITEM_DATA_ROLE_DOWNLOAD_SPEED);
}

void MainWindow::hideUnknownItem()
{
    for (int rowIndex = 0; rowIndex < m_listViewItemModel->rowCount(); rowIndex++) {
        const ProcInfo infoTmp = getInfoFromModel(rowIndex);
        if (0 == infoTmp.nPid) {
            m_listViewItemModel->removeRow(rowIndex);
            break;
        }
    }
}
